home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / daten / ispell / source / addons / nextispell / nextispell.m < prev    next >
Text File  |  1995-01-23  |  10KB  |  476 lines

  1. /* nextispell.m */
  2. /*
  3.  *
  4.  * Modify the code anyway you like and report changes
  5.  * as well as any good ideas to me, willers@butp.unibe.ch
  6.  *
  7.  * written by Moritz Willers
  8.  *
  9.  */
  10.  
  11. #define DATE "4. Januar 1994\n"
  12. #define VERSION "Version 0.4\n"
  13.  
  14. #import <appkit/appkit.h>
  15. #import "configure.h"
  16.  
  17. #define MAXBUFLEN 1024
  18.  
  19. struct pipe_with_buf {
  20.     int fd;
  21.     char *buf;
  22. };
  23.  
  24. mutex_t lock;
  25. char misspelled[MAXBUFLEN];
  26.  
  27. @interface Dictionaire:Object
  28. {
  29.     int fromIspell, toIspell, fromDictionaire, toDictionaire;
  30. }
  31.  
  32. - init;
  33. - free;
  34.  
  35. - (BOOL)spellServer:(NXSpellServer *)sender 
  36.     findMisspelledWord:(int *)start 
  37.     length:(int *)length 
  38.     inLanguage:(const char *)language
  39.     inTextStream:(id <NXReadOnlyTextStream>)textStream 
  40.     startingAt:(int)startPosition
  41.     wordCount:(int *)number 
  42.     countOnly:(BOOL)flag;
  43. - (void)spellServer:(NXSpellServer *)sender 
  44.     suggestGuessesForWord:(const char *)word 
  45.     inLanguage:(const char *)language;
  46.  
  47. @end
  48.  
  49.  
  50. @implementation Dictionaire
  51.  
  52. /* ********************     private functions     ************************ */
  53.  
  54. int makepipe(int *rd, int *wrt)
  55. {
  56.      int     piperesult, fildes[2];
  57.  
  58.      piperesult = pipe(fildes);
  59.  
  60.      *rd = fildes[0];
  61.      *wrt = fildes[1];
  62.  
  63.      return piperesult;
  64. }
  65.  
  66. int secure_read(int d, char *buf, int nbytes)
  67. {
  68.  
  69. /* someday I'm going to rewrite this using the select() call instead of a nonblocking fd */
  70.  
  71.     int ret, reads = 0;
  72.     do
  73.     {
  74.     ret = read(d, buf, nbytes-1);
  75.     reads++;
  76.     } while ((ret == -1) && (reads < 100000));
  77.     if (reads < 100000)
  78.     {
  79.     return ret;
  80.     }
  81.     else
  82.     fprintf(stderr, "%s: Couldn't read from pipe: %s\n", *NXArgv, strerror(errno));
  83.     exit(1);
  84. }
  85.  
  86. void empty_pipe(struct pipe_with_buf *pointerTopwb)
  87. {
  88.     int len;
  89.     int fd = pointerTopwb->fd;
  90.     char buf[MAXBUFLEN];
  91.     char *bufptr;
  92.     
  93.     mutex_lock(lock);
  94.     
  95.     strcpy(buf, pointerTopwb->buf);
  96.     
  97.     bufptr = strrchr(buf, '\n');
  98.     if (bufptr)
  99.     bufptr--;
  100.     else
  101.     bufptr = buf;
  102.     while (*bufptr != '\n')
  103.     {
  104.     len = secure_read(fd, buf, MAXBUFLEN);
  105.     buf[len] = '\0';
  106.     bufptr = strrchr(buf, '\n');
  107.     if (bufptr)
  108.         bufptr--;
  109.     else
  110.         bufptr = buf;
  111.     }
  112.     
  113.     mutex_unlock(lock);
  114. }
  115.  
  116.  
  117. /* ******************************************************************** */
  118.  
  119. - init
  120. {        
  121.     int fdstate;
  122.     
  123.     [super init];
  124.     
  125.     lock = mutex_alloc();
  126.     *misspelled = '\0';
  127.     
  128.     if (makepipe(&fromIspell,&toDictionaire)) 
  129.     {
  130.     fprintf(stderr, "%s: Couldn't create pipe: %s\n", *NXArgv, strerror(errno));
  131.     [self free];
  132.     return nil; // init wasn't successful
  133.     }
  134.     if (makepipe(&fromDictionaire,&toIspell))
  135.     {
  136.     fprintf(stderr, "%s: Couldn't create pipe: %s\n", *NXArgv, strerror(errno));
  137.     [self free];
  138.     return nil; // init wasn't successful
  139.     }
  140.     
  141.  
  142.     switch (fork())
  143.     {
  144.     case -1:
  145.         fprintf(stderr, "%s: Couldn't fork: %s\n", *NXArgv, strerror(errno));
  146.         [self free];
  147.         return nil;
  148.     case  0:
  149.         close(toIspell);
  150.         close(fromIspell);
  151.         
  152.         if ( dup2(fromDictionaire, 0) == -1 )
  153.         fprintf(stderr, "%s: Error establishing read pipe: %s\n", *NXArgv, strerror(errno));
  154.         if ( dup2(toDictionaire, 1) == -1 )
  155.         fprintf(stderr, "%s: Error establishing write pipe: %s\n", *NXArgv, strerror(errno));
  156.         
  157.         /* change child into ispell */
  158.         execlp(ISPELL, NULL);
  159.         fprintf(stderr, "%s: Failed to exec ispellpipe: %s\n", *NXArgv, strerror(errno));
  160.         exit(1);
  161.     default:
  162.         close(fromDictionaire);
  163.         close(toDictionaire);
  164.                 
  165.         /* set fromIspell fd non blocking: */
  166.         fdstate = fcntl(fromIspell, F_GETFL, 0);
  167.         fcntl(fromIspell, F_SETFL, fdstate|O_NDELAY);
  168.         
  169. #ifdef TEX
  170.         write(toIspell, "+\n", 2);
  171. #endif
  172.         
  173.         break;
  174.     }
  175.     return self;
  176. }
  177.  
  178. - free
  179. {
  180.     char eof = EOF;
  181.     
  182.     if (toIspell)
  183.     {
  184.     write(toIspell, &eof, 1);
  185.     close(toIspell);
  186.     }
  187.     if (fromIspell) close(fromIspell); 
  188.     
  189.     return [super free];
  190. }
  191.  
  192. /* ***********************    delegate methods    ************************* */
  193.  
  194. - (BOOL)spellServer:(NXSpellServer *)sender 
  195.     findMisspelledWord:(int *)start 
  196.     length:(int *)length 
  197.     inLanguage:(const char *)language
  198.     inTextStream:(id <NXReadOnlyTextStream>)textStream 
  199.     startingAt:(int)startPosition
  200.     wordCount:(int *)number 
  201.     countOnly:(BOOL)flag
  202. {
  203.     char readbuf[MAXBUFLEN], writebuf[MAXBUFLEN];
  204.     char *readbufptr, *writebufptr;
  205.     int otherlen, len;
  206.     int offset, linelength = 0;
  207.     char misspelledWord[MAXBUFLEN];
  208.     BOOL repeatLoop;
  209.     struct pipe_with_buf pwb;
  210.     
  211.     if (flag)
  212.     {
  213.     *number = -1; /* is not able to do pure wordcounting */
  214.     return NO;
  215.     }
  216.     
  217.     if ([textStream isAtEOTS])
  218.     return NO;
  219.     
  220.     mutex_lock(lock); /* to make sure the thread has emptied the pipe */
  221.     mutex_unlock(lock);
  222.     
  223.     readbufptr = readbuf;
  224.     *start = startPosition;
  225.     
  226.     /* set stream outside a word */
  227.     [textStream readCharacters:readbufptr count:1];
  228.     while (!NXIsSpace(*readbufptr) && startPosition && ![textStream isAtEOTS])
  229.     {
  230.     [textStream readCharacters:readbufptr count:1];
  231.     (*start)++;
  232.     }
  233.     if (*readbufptr == '\n') *readbufptr = ' ';
  234.     readbufptr++;
  235.     len = 1;
  236.     
  237.     /* main loop */
  238.     do
  239.     {
  240.     /* read the 80 characters form the text stream and complete the last word */
  241.     len += [textStream readCharacters:readbufptr count:80];
  242.     readbufptr = readbuf;
  243.     readbufptr[len] = '\0';
  244.     while (*readbufptr)
  245.     {
  246.         if (*readbufptr == '\n')
  247.         *readbufptr = ' ';
  248.         readbufptr++;
  249.     }
  250.     
  251.     if (len>=80)
  252.         while (!(NXIsSpace(*(readbufptr-1)) || [textStream isAtEOTS]))
  253.         {
  254.         [textStream readCharacters:readbufptr count:1];
  255.         len++;
  256.         if (*readbufptr == '\n')
  257.             *readbufptr = ' ';
  258.         readbufptr++;
  259.         }
  260.     *readbufptr++ = '\n';
  261.     *readbufptr = '\0';
  262.     linelength = len;
  263.     len = 0;
  264.     readbufptr = readbuf;
  265.         
  266.  
  267.     /* send ispell the next ca. 80 chars */
  268.     write(toIspell, "^", 1);
  269.     while (*readbufptr)
  270.         write(toIspell, readbufptr++, 1);
  271.         
  272.     readbufptr = readbuf;
  273.  
  274.     repeatLoop = YES;
  275.     do
  276.     {
  277.         otherlen = secure_read(fromIspell, writebuf, MAXBUFLEN);
  278.         writebuf[otherlen] = '\0';
  279.         writebufptr = writebuf;
  280.         while (writebufptr && *writebufptr)
  281.         {
  282.         /* make sure a whole line is ready to be processed */
  283.         while (!strchr(writebufptr, '\n'))
  284.         {
  285.             /* add more to the buffer */
  286.             strcpy(writebuf, writebufptr);
  287.             writebufptr = strchr(writebuf, '\0');
  288.             otherlen = secure_read(fromIspell, writebufptr, MAXBUFLEN - strlen(writebuf));
  289.             writebufptr[otherlen] = '\0';
  290.             writebufptr = writebuf;
  291.         }
  292.         /* then process the line: */
  293.         switch(*writebufptr)
  294.         {
  295.             case '*':
  296.             case '+':
  297.             case '-':
  298.             (*number)++;
  299.             break;
  300.             case '&':
  301.             case '?':
  302.             strcpy(misspelled, writebufptr);
  303.             writebufptr += 2;
  304.             sscanf(writebufptr, "%s %*d %d", misspelledWord, &offset);
  305.             if ([sender isInUserDictionary:(const char *)misspelledWord caseSensitive:NO])
  306.             {
  307.                 (*number)++;
  308.                 break;
  309.             }
  310.             *length = strlen(misspelledWord);
  311.             *start += offset - 1;
  312.             
  313.             pwb.fd = fromIspell;
  314.             pwb.buf = writebuf;
  315.             cthread_detach(cthread_fork( (cthread_fn_t)empty_pipe, (any_t)&pwb));
  316.             return YES;
  317.             case '#':
  318.             strcpy(misspelled, writebufptr);
  319.             writebufptr += 2;
  320.             sscanf(writebufptr, "%s %d", misspelledWord, &offset);
  321.             if ([sender isInUserDictionary:(const char *)misspelledWord caseSensitive:NO])
  322.             {
  323.                 (*number)++;
  324.                 break;
  325.             }
  326.             *length = strlen(misspelledWord);
  327.             *start += offset - 1; 
  328.             pwb.fd = fromIspell;
  329.             pwb.buf = writebuf;
  330.             cthread_detach(cthread_fork( (cthread_fn_t)empty_pipe, (any_t)&pwb));
  331.             return YES;
  332.             case '\n':
  333.             *start += linelength;
  334.             linelength = 0;
  335.             repeatLoop = NO;
  336.             default:
  337.             break;
  338.         }
  339.         writebufptr = strchr(writebufptr, '\n');
  340.         if (writebufptr)
  341.             writebufptr++;
  342.         }
  343.     } while (repeatLoop);
  344.     }
  345.     while (![textStream isAtEOTS]);
  346.  
  347.         
  348.     return NO; /* no misspelled words found */
  349. }
  350.  
  351. - (void)spellServer:(NXSpellServer *)sender 
  352.     suggestGuessesForWord:(const char *)word 
  353.     inLanguage:(const char *)language
  354. {
  355.     int len, misscount;
  356.     char buf[MAXBUFLEN];
  357.     char *bufptr, *guess;
  358.     
  359.     if (*misspelled)
  360.     {
  361.     bufptr = strchr(misspelled, '\n');
  362.     bufptr++;
  363.     *bufptr = '\0';
  364.     switch (*misspelled)
  365.     {
  366.         case '&':
  367.         case '?':
  368.         bufptr = strchr(misspelled + 2, ' ') + 1;
  369.         misscount = atoi(bufptr);
  370.         bufptr = strchr(misspelled, ':');
  371.         while (bufptr != NULL  &&  misscount > 0)
  372.         {
  373.             misscount--;
  374.             guess = bufptr + 2;
  375.             if (bufptr = strchr(guess, ','))
  376.             *bufptr = '\0';
  377.             else
  378.             {
  379.             bufptr = strchr(guess, '\n');
  380.             *bufptr = '\0';
  381.             bufptr = NULL;
  382.             }
  383.             [sender addGuess:guess];
  384.         }
  385.         case '#':
  386.         ; /* no guesses */
  387.     }
  388.     *misspelled = '\0';
  389.     return;
  390.     } /* else */
  391.     
  392.     mutex_lock(lock); /* make sure that the pipe has been emptied */
  393.     mutex_unlock(lock);
  394.     
  395.     write(toIspell, "^", 1);
  396.     write(toIspell, word, strlen(word));
  397.     write(toIspell, "\n", 1);
  398.     
  399.     bufptr = buf;
  400.     *buf = '\0';
  401.     do
  402.     {
  403.     len = secure_read(fromIspell, bufptr, MAXBUFLEN - strlen(buf));
  404.     bufptr[len] = '\0';
  405.     if (strchr(buf, '\n') == strrchr(buf, '\n'))
  406.         bufptr = strchr(buf, '\0');
  407.     else
  408.         bufptr = buf;
  409.     } while (!(*bufptr));
  410.     
  411.     switch (*bufptr)
  412.     {
  413.     case '*':
  414.     case '+':
  415.     case '-':
  416.         [sender addGuess:word];
  417.         break;
  418.     case '&':
  419.     case '?':
  420.         bufptr = strchr(bufptr + 2, ' ') + 1;
  421.         misscount = atoi(bufptr);
  422.         bufptr = strchr(bufptr, ':');
  423.         while (bufptr != NULL  &&  misscount > 0)
  424.         {
  425.         misscount--;
  426.         guess = bufptr + 2;
  427.         if (bufptr = strchr(guess, ','))
  428.             *bufptr = '\0';
  429.         else
  430.         {
  431.             bufptr = strchr(guess, '\n');
  432.             *bufptr = '\0';
  433.             bufptr = NULL;
  434.         }
  435.         [sender addGuess:guess];
  436.         }
  437.     case '#':
  438.         ; /* no guesses */
  439.     }
  440.     
  441.     return;
  442. }
  443.  
  444. @end
  445.  
  446. /* **************************     main     ******************************* */
  447.  
  448. void main(int argc, char **argv)
  449. {
  450.     NXSpellServer *aServer;
  451.     
  452.     if (argc > 1)
  453.     {
  454.     if (!strcmp((argv[1]), "-v"))
  455.     {
  456.         printf("nextispell by Moritz Willers\n");
  457.         printf("email: willers@butp.unibe.ch (NeXTMail)\n");
  458.         printf(VERSION);
  459.         printf(DATE);
  460.         exit(0);
  461.     } else
  462.     {
  463.         fprintf(stderr, "Usage: %s [-v]\n", *argv);
  464.         exit(0);
  465.     }
  466.     }
  467.     aServer = [[NXSpellServer alloc] init];
  468.     if ([aServer registerLanguage:LANGUAGE byVendor:VENDOR]) {
  469.     [aServer setDelegate:[[Dictionaire alloc] init]];
  470.     [aServer run];
  471.     fprintf(stderr, "Unexpected death of %s!\n", *argv);
  472.     } else {
  473.     fprintf(stderr, "Unable to check in %s.\n", *argv);
  474.     }
  475. }
  476.